﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using TmU220PrintHelperV2d0.Entity;
using ZhangLogSysV1d0;

namespace TmU220PrintHelperV2d0.Service
{
    /// <summary>
    /// 打印机的打印工具类
    /// </summary>
    public class PrinterUtilityV2d0
    {
       
        /// <summary>
        /// 得到文本图像的高度和宽度，如果宽度大于400像素则无法打印
        /// </summary>
        /// <param name="text">待打印文本</param>
        /// <param name="printFont">打印字体</param>
        /// <returns>文本图像的高度和宽度</returns>
        private static SizeF GetWidthHeightOfTextImage(string text,Font printFont)
        {
            SizeF textSizeF=new SizeF();
            try
            {
                Bitmap textBitmap = new Bitmap(400, 24);
                Graphics iG = Graphics.FromImage(textBitmap);
                //计算该字符串使用该字体时，不换行时宽度为多少像素，高度为多少像素
                textSizeF = iG.MeasureString(text, printFont);
                float width = textSizeF.Width;
                float height = textSizeF.Height;
                iG.Dispose();
                textBitmap.Dispose();
                //如果字符串宽度大于400，则无法进行打印
                if (width > 400) textSizeF = new SizeF(0,0);
            }
            catch(Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            return textSizeF;
        }

        /// <summary>
        /// 根据文本内容，字体，对齐方式，图像宽度，得到位图(位图高度是自动计算的)
        /// </summary>
        /// <param name="text">用图像模式进行打印的文本</param>
        /// <param name="leftSpace">左边距</param>
        /// <param name="printFont">打印字体</param>
        /// <param name="align">对齐方式</param>
        /// <param name="imageWidth">图像像素宽度</param>
        /// <returns>位图</returns>
        public static Bitmap GetAutoHeightBitmapFromText(string text, Font printFont,string align, int imageWidth = 400)
        {
            //得到适应文本的图像的高度和宽度
            SizeF textWidthHeight = GetWidthHeightOfTextImage(text, printFont);
            int textWidth = (int)Math.Ceiling(textWidthHeight.Width);
            int textHeight= (int)Math.Ceiling(textWidthHeight.Height);
            //垂直居中，水平对齐方式依据align
            //图形的实际高度
            int imageHeight = (int)(Math.Ceiling(textHeight / 8.0)) * 8;//8的整数倍
            //上边距
            int topSpace = (imageHeight - textHeight) / 2;

            Point pointLT = new Point(0, 0);
            if (align == "Left")
            {
                pointLT.X = 0;
                pointLT.Y = topSpace;
            }
            else if (align == "Right")
            {
                pointLT.X = imageWidth- textWidth;
                pointLT.Y = topSpace;
            }
            else
            {
                pointLT.X = (imageWidth - textWidth)/2;
                pointLT.Y = topSpace;
            }
            Bitmap textBitmap = new Bitmap(imageWidth, imageHeight);
            Graphics iG = Graphics.FromImage(textBitmap);
            Brush fontBrush = new SolidBrush(Color.Black);
            iG.Clear(Color.White);        //赋予图像一个背景色
            iG.DrawString(text, printFont, fontBrush, new Rectangle(pointLT.X, pointLT.Y, imageWidth, imageHeight));
            iG.Dispose();
            return textBitmap;
        }
        /// <summary>
        /// 把一张32X256 Bitmap图片转化为打印机可以打印的bit
        /// </summary>
        /// <param name="bit"></param>
        /// <returns></returns>
        public static byte[] pic2PxPoint(Bitmap bit)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int x1 = bit.Width;
            int y1 = bit.Height;
            int heightPixels = 24;
            int widthPixels = 256;
            byte[] data = new byte[(256 + 6) * 3];
            int k = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            data[2] = 0; // m=0 选择8点單密度打印，每列可以打印8個點。
            byte tmu220Width = 198;
            data[3] = tmu220Width;//198列
            data[4] = 1;//4行
            k = 4;
            for (int j = 0; j < 2; j++)
            {
                for (int i = 0; i < tmu220Width + 1; i++)
                {
                    k++;
                    byte[] by = new byte[8];
                    for (int n = 0; n < 8; n++)
                    {
                        byte b = px2Byte(i, j * 8 + 7 - n, bit);
                        if (i > 198) b = 0;
                        by[n] = b;
                    }
                    data[k] = (byte)changePointPx1(by);
                }
            }
            return data;
        }
        public static byte[] pic2PxPoint(Bitmap bit, int rowIndex)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int x1 = bit.Width;
            int y1 = bit.Height;
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = 128;
            byte nH = 1;
            byte[] data = new byte[nL + nL * (nH + 1) + 5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            data[2] = 1; // m=0 选择8点單密度打印，每列可以打印8個點。
            byte tmu220Width = 200;
            data[3] = (byte)(widthPixels % 255);// tmu220Width;//200列
            data[4] = 1;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < 128)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        //data[i + j * 128 + 5] = (byte)changePointPx1(by);
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }
        /// <summary>
        /// 8点单密度 
        /// //tm-u220圖形打印模式是8點單密度
            //位图的宽和高，宽度固定为200，高度应为8的整数倍
        /// </summary>
        /// <param name="bit">位图</param>
        /// <param name="rowIndex">8像素高度为一条水平扫描线，第几条薯片扫描线，从top第一条水平扫描线为0</param>
        /// <returns></returns>
        public static byte[] pic2PxPoint8NeedleSingleDensity(Bitmap bit, int rowIndex)
        {

            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = (byte)(widthPixels - 256);
            byte nH = 1;
            int dataByteArraySize = nL+nH  * 256 + 5;
            //byte[] data = new byte[nL + nL * (nH + 1) + 5];
            byte[] data = new byte[nL + 256 * (nH) + 5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            data[0] = 0x1B;
            data[1] = 0x2A;
            //m=0 8点单密度默认边距条件下,可以打印像素宽度为200以内的图片
            //m=1 8点双密度默认边距条件下,可以打印像素宽度为400以内的图片
            data[2] = 0; // m=0 选择8点单密度打印，每列可以打印8個點。
            data[3] = nL;// tmu220Width;//200列
            data[4] = nH;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < widthPixels)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }
        /// <summary>
        /// 8点双密度,打印针垂直有8根针，每根针对应一个像素点。一行可以最多打印400像素宽的图像
        /// tm-u220圖形打印模式是8點双密度
        /// 位图的宽和高，宽度固定为400，高度应为8的整数倍
        /// </summary>
        /// <param name="bit">位图</param>
        /// <param name="rowIndex">8像素高度为一条水平扫描线，第几条薯片扫描线，从0开始</param>
        /// <returns></returns>
        public static byte[] pic2PxPoint8NeedleDoubleDensity(Bitmap bit, int rowIndex)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = (byte)(widthPixels - 256);//一个存储行,最多256列.400列需要分成两部分
            byte nH = (byte)(1+ widthPixels/256);
            int dataByteArraySize = nL+nH  * 256 + 5;//总数据个数
            //byte[] data = new byte[nL + nL * (nH + 1) + 5];
            byte[] data = new byte[dataByteArraySize];
            for (int i = 0; i < data.Count(); i++) data[i] = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            //m=0 8点单密度默认边距条件下,可以打印像素宽度为200以内的图片
            //m=1 8点双密度默认边距条件下,可以打印像素宽度为400以内的图片
            data[2] = 1; // m=1 选择8点双密度打印，每列可以打印8個點。
            data[3] = nL;// tmu220Width;//200列
            data[4] = nH;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < widthPixels)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            //自下而上
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }


        /// <summary>
        /// 将[1,0,0,1,0,0,0,1]这样的二进制转为化十进制的数值（效率更高）,核心方法
        /// </summary>
        /// <param name="arry"></param>
        /// <returns></returns>
        public static int changePointPx1(byte[] arry)
        {
            int v = 0;
            for (int j = 0; j < arry.Length; j++)
            {
                if (arry[j] == 1)
                {
                    v = v | 1 << j;
                }
            }
            return v;
        }
        /// <summary>
        ///图片二值化，黑色是1，白色是0 核心方法
        /// </summary>
        /// <param name="x">横坐标</param>
        /// <param name="y">纵坐标</param>
        /// <param name="bit">位图</param>
        /// <returns></returns>
        public static byte px2Byte(int x, int y, Bitmap bitmap)
        {
            byte b;
            Color pixel = bitmap.GetPixel(x, y);
            int gray = RGB2Gray(pixel.R, pixel.G, pixel.B);
            if (gray < 128)
            {
                b = 1;
            }
            else
            {
                b = 0;
            }
            return b;
        }

        /// <summary>
        /// 图片灰度的转化 核心方法
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static int RGB2Gray(int r, int g, int b)
        {
            int gray = (int)(0.29900 * r + 0.58700 * g + 0.11400 * b);  //灰度转化公式
            return gray;
        }
    }
}
